home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_100 / 198_02 / search.c < prev    next >
C/C++ Source or Header  |  1990-01-21  |  42KB  |  1,780 lines

  1. /*
  2.  * The functions in this file implement commands that search in the forward
  3.  * and backward directions.  There are no special characters in the search
  4.  * strings.  Probably should have a regular expression search, or something
  5.  * like that.
  6.  *
  7.  * Aug. 1986 John M. Gamble:
  8.  *    Made forward and reverse search use the same scan routine.
  9.  *
  10.  *    Added a limited number of regular expressions - 'any',
  11.  *    'character class', 'closure', 'beginning of line', and
  12.  *    'end of line'.
  13.  *
  14.  *    Replacement metacharacters will have to wait for a re-write of
  15.  *    the replaces function, and a new variation of ldelete().
  16.  *
  17.  *    For those curious as to my references, i made use of
  18.  *    Kernighan & Plauger's "Software Tools."
  19.  *    I deliberately did not look at any published grep or editor
  20.  *    source (aside from this one) for inspiration.  I did make use of
  21.  *    Allen Hollub's bitmap routines as published in Doctor Dobb's Journal,
  22.  *    June, 1985 and modified them for the limited needs of character class
  23.  *    matching.  Any inefficiences, bugs, stupid coding examples, etc.,
  24.  *    are therefore my own responsibility.
  25.  *
  26.  * April 1987: John M. Gamble
  27.  *    Deleted the "if (n == 0) n = 1;" statements in front of the
  28.  *    search/hunt routines.  Since we now use a do loop, these
  29.  *    checks are unnecessary.  Consolidated common code into the
  30.  *    function delins().  Renamed global mclen matchlen,
  31.  *    and added the globals matchline, matchoff, patmatch, and
  32.  *    mlenold.
  33.  *    This gave us the ability to unreplace regular expression searches,
  34.  *    and to put the matched string into an evironment variable.
  35.  *    SOON TO COME: Meta-replacement characters!
  36.  *
  37.  *    25-apr-87    DML
  38.  *    - cleaned up an unneccessary if/else in forwsearch() and
  39.  *      backsearch()
  40.  *    - savematch() failed to malloc room for the terminating byte
  41.  *      of the match string (stomp...stomp...). It does now. Also
  42.  *      it now returns gracefully if malloc fails
  43.  *
  44.  *    July 1987: John M. Gamble
  45.  *    Set the variables matchlen and matchoff in the 'unreplace'
  46.  *    section of replaces().  It would confuse the function
  47.  *    savematch() if you replaced, unreplaced, then replaced
  48.  *    again (serves you right for being so wishy-washy...)
  49.  */
  50.  
  51. #include        <stdio.h>
  52. #include    "estruct.h"
  53. #include        "edef.h"
  54.  
  55. #if    LATTICE | C86 | DECUSC
  56. #define    void    int
  57. #endif
  58.  
  59. #if    C86
  60. #define    STATIC    /* */
  61. #else
  62. #if    DECUSC
  63. #define    STATIC    extern
  64. #else
  65. #define    STATIC    static
  66. #endif
  67. #endif
  68.  
  69.     /* UCAST must map a possibly signed char to an unsigned value */
  70.     /* In standard C, (unsigned int) will sign extend first like (int) */
  71.     /* Not all compilers understand (unsigned char) */
  72.  
  73. #if    LATTICE | C86 | DECUSC | BSD29 | V7 | CPM | WMCS
  74. #define    UCAST    (unsigned int)
  75. #else
  76. #define    UCAST    (unsigned char)
  77. #endif
  78.  
  79. STATIC int    amatch();
  80. STATIC int    readpattern();
  81. STATIC int    replaces();
  82. STATIC int    nextch();
  83. STATIC int    mcstr();
  84. STATIC int    mceq();
  85. STATIC int    cclmake();
  86. STATIC int    biteq();
  87. #if    MAGIC
  88. STATIC void     setbit();
  89. STATIC BITMAP   clearbits();
  90. #endif
  91.  
  92. #if    DECUSC
  93. #define    STATIC    /* */
  94. #endif
  95.  
  96. static int deltaf[HICHAR], deltab[HICHAR];
  97. static int lastchfjump, lastchbjump;
  98. static int patlenadd;
  99.  
  100. /*
  101.  * forwsearch -- Search forward.  Get a search string from the user, and
  102.  *    search for the string.  If found, reset the "." to be just after
  103.  *    the match string, and (perhaps) repaint the display.
  104.  */
  105.  
  106. forwsearch(f, n)
  107. int f, n;    /* default flag / numeric argument */
  108. {
  109.     register int status;
  110.  
  111.     status = TRUE;
  112.  
  113.     /* If n is negative, search backwards.
  114.      * Otherwise proceed by asking for the search string.
  115.      */
  116.     if (n < 0)
  117.         return(backsearch(f, -n));
  118.  
  119.     /* Ask the user for the text of a pattern.  If the
  120.      * response is TRUE (responses other than FALSE are
  121.      * possible), search for the pattern for as long as
  122.      * n is positive (n == 0 will go through once, which
  123.      * is just fine).
  124.      */
  125.     if ((status = readpattern("Search", &pat[0], TRUE)) == TRUE) {
  126.         do {
  127. #if    MAGIC
  128.             if (magical && (curwp->w_bufp->b_mode & MDMAGIC) != 0)
  129.                 status = mcscanner(&mcpat[0], FORWARD, PTEND);
  130.             else
  131. #endif
  132.                 status = scanner(&pat[0], FORWARD, PTEND);
  133.         } while ((--n > 0) && status);
  134.  
  135.         /* Save away the match, or complain
  136.          * if not there.
  137.          */
  138.         if (status != TRUE)
  139.             mlwrite("Not found");
  140.     }
  141.     return(status);
  142. }
  143.  
  144. /*
  145.  * forwhunt -- Search forward for a previously acquired search string.
  146.  *    If found, reset the "." to be just after the match string,
  147.  *    and (perhaps) repaint the display.
  148.  */
  149.  
  150. forwhunt(f, n)
  151. int f, n;    /* default flag / numeric argument */
  152. {
  153.     register int status;
  154.  
  155.     status = TRUE;
  156.  
  157.     if (n < 0)        /* search backwards */
  158.         return(backhunt(f, -n));
  159.  
  160.     /* Make sure a pattern exists, or that we didn't switch
  161.      * into MAGIC mode until after we entered the pattern.
  162.      */
  163.     if (pat[0] == '\0')
  164.     {
  165.         mlwrite("No pattern set");
  166.         return (FALSE);
  167.     }
  168. #if    MAGIC
  169.     if ((curwp->w_bufp->b_mode & MDMAGIC) != 0 &&
  170.          mcpat[0].mc_type == MCNIL)
  171.     {
  172.         if (!mcstr())
  173.             return (FALSE);
  174.     }
  175. #endif
  176.  
  177.     /* Search for the pattern for as long as
  178.      * n is positive (n == 0 will go through once, which
  179.      * is just fine).
  180.      */
  181.     do
  182.     {
  183. #if    MAGIC
  184.         if (magical && (curwp->w_bufp->b_mode & MDMAGIC) != 0)
  185.             status = mcscanner(&mcpat[0], FORWARD, PTEND);
  186.         else
  187. #endif
  188.             status = scanner(&pat[0], FORWARD, PTEND);
  189.     } while ((--n > 0) && status);
  190.  
  191.     /* Save away the match, or complain
  192.      * if not there.
  193.      */
  194.     if (status != TRUE)
  195.         mlwrite("Not found");
  196.  
  197.     return(status);
  198. }
  199.  
  200. /*
  201.  * backsearch -- Reverse search.  Get a search string from the user, and
  202.  *    search, starting at "." and proceeding toward the front of the buffer.
  203.  *    If found "." is left pointing at the first character of the pattern
  204.  *    (the last character that was matched).
  205.  */
  206. backsearch(f, n)
  207. int f, n;    /* default flag / numeric argument */
  208. {
  209.     register int status;
  210.  
  211.     status = TRUE;
  212.  
  213.     /* If n is negative, search forwards.
  214.      * Otherwise proceed by asking for the search string.
  215.      */
  216.     if (n < 0)
  217.         return(forwsearch(f, -n));
  218.  
  219.     /* Ask the user for the text of a pattern.  If the
  220.      * response is TRUE (responses other than FALSE are
  221.      * possible), search for the pattern for as long as
  222.      * n is positive (n == 0 will go through once, which
  223.      * is just fine).
  224.      */
  225.     if ((status = readpattern("Reverse search", &pat[0], TRUE)) == TRUE) {
  226.         do {
  227. #if    MAGIC
  228.             if (magical && (curwp->w_bufp->b_mode & MDMAGIC) != 0)
  229.                 status = mcscanner(&tapcm[0], REVERSE, PTBEG);
  230.             else
  231. #endif
  232.                 status = scanner(&tap[0], REVERSE, PTBEG);
  233.         } while ((--n > 0) && status);
  234.  
  235.         /* Save away the match, or complain
  236.          * if not there.
  237.          */
  238.         if (status != TRUE)
  239.             mlwrite("Not found");
  240.     }
  241.     return(status);
  242. }
  243.  
  244. /*
  245.  * backhunt -- Reverse search for a previously acquired search string,
  246.  *    starting at "." and proceeding toward the front of the buffer.
  247.  *    If found "." is left pointing at the first character of the pattern
  248.  *    (the last character that was matched).
  249.  */
  250. backhunt(f, n)
  251.  
  252. int f, n;    /* default flag / numeric argument */
  253.  
  254. {
  255.     register int    status;
  256.  
  257.     status = TRUE;
  258.  
  259.     if (n < 0)
  260.         return(forwhunt(f, -n));
  261.  
  262.     /* Make sure a pattern exists, or that we didn't switch
  263.      * into MAGIC mode until after we entered the pattern.
  264.      */
  265.     if (tap[0] == '\0')
  266.     {
  267.         mlwrite("No pattern set");
  268.         return (FALSE);
  269.     }
  270. #if    MAGIC
  271.     if ((curwp->w_bufp->b_mode & MDMAGIC) != 0 &&
  272.          tapcm[0].mc_type == MCNIL)
  273.     {
  274.         if (!mcstr())
  275.             return (FALSE);
  276.     }
  277. #endif
  278.  
  279.     /* Go search for it for as long as
  280.      * n is positive (n == 0 will go through once, which
  281.      * is just fine).
  282.      */
  283.     do
  284.     {
  285. #if    MAGIC
  286.         if (magical && (curwp->w_bufp->b_mode & MDMAGIC) != 0)
  287.             status = mcscanner(&tapcm[0], REVERSE, PTBEG);
  288.         else
  289. #endif
  290.             status = scanner(&tap[0], REVERSE, PTBEG);
  291.     } while ((--n > 0) && status);
  292.  
  293.     /* Save away the match, or complain
  294.      * if not there.
  295.      */
  296.     if (status != TRUE)
  297.         mlwrite("Not found");
  298.  
  299.     return(status);
  300. }
  301.  
  302. #if    MAGIC
  303. /*
  304.  * mcscanner -- Search for a meta-pattern in either direction.  If found,
  305.  *    reset the "." to be at the start or just after the match string